package net.googlecode.demenkov.controllers;

import net.googlecode.demenkov.domains.*;
import net.googlecode.demenkov.services.FriendshipService;
import net.googlecode.demenkov.services.PersonService;
import net.googlecode.demenkov.utils.PersonComparatorByRating;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Controller for actions with persons, groupmates, groups,  faculties, universities, friendships and friends
 *
 * @author Demenkov Yura
 */
@Controller
public class FriendController {
    @Autowired
    private PersonService personService;
    @Autowired
    private FriendshipService friendshipService;
    protected final Logger logger = Logger.getLogger(FriendController.class);

    /**
     * Gets authorizated person's email
     *
     * @return person's email
     */
    private String getUserEmail() {
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        return ((UserDetails) principal).getUsername();
    }

    /**
     * Looking for person with personal Id from request parameters and returns page with his personal information.
     *
     * @param personId of person
     * @param request  with parametrs for view-page
     * @return person's page or your home page, if there are no person with this PersonId
     *         or PersonId=your own Id
     */
    @RequestMapping(value = "/persons/{personId}")
    public String viewPerson(@PathVariable("personId") int personId,
                             HttpServletRequest request, Map model) {
        Person person = personService.getPerson(personId);
        if (person != null) {
            Person fromPerson = personService.findPersonByEmail(getUserEmail());
            if (fromPerson.getPersonId() != person.getPersonId()) {
                if (fromPerson.getPersonsAreVotedByThisPerson().contains(person)) {
                    request.setAttribute("addvote", false);
                } else {
                    request.setAttribute("addvote", true);
                }
                if (fromPerson.getAllFriends().contains(person)) {
                    request.setAttribute("addfriend", false);
                    if (fromPerson.getConfirmedFriends().contains(person)) {
                        request.setAttribute("confirmed", true);
                    } else {
                        request.setAttribute("confirmed", false);
                    }
                } else {
                    request.setAttribute("addfriend", true);
                }
                model.put("msg", request.getParameter("msg"));
                request.setAttribute("person", person);
                return "/person";
            } else {
                return "redirect:/home";
            }
        } else {
            logger.info("There are no person with id=" + personId);
            return "redirect:/home";
        }
    }

    /**
     * Looking for group with groupId from request parameters and returns page with group's information
     *
     * @param groupId of group
     * @param request with parametrs for view-page
     * @return group's page with it's students or your home page, if there are no group with this groupId
     */
    @RequestMapping(value = "/groups/{groupId}")
    public String viewGroup(@PathVariable("groupId") int groupId, HttpServletRequest request) {
        Group group = personService.getGroup(groupId);
        if (group != null) {
            request.setAttribute("group", group);
            List<Person> groupmates = new ArrayList<Person>(group.getPersons());
            Collections.sort(groupmates, new PersonComparatorByRating());
            request.setAttribute("groupmates", groupmates);
            return "/group";
        } else {
            logger.info("There are no group with id=" + groupId);
            return "redirect:/home";
        }
    }

    /**
     * Redirects to page with user's faculty groups
     *
     * @param request
     * @return faculty page
     */
    @RequestMapping(value = "/groups")
    public String viewGroups(HttpServletRequest request) {
        return "redirect:/faculties/" + personService.findPersonByEmail(getUserEmail())
                .getGroup().getFaculty().getFacultyId();
    }


    /**
     * Looking for faculty with facultyId from request parameters and returns page with faculty's information
     *
     * @param facultyId of faculty
     * @param request   with parametrs for view-page
     * @return faculty's page with it's groups and top-students or your home page, if there are no faculty with this facultyId
     */
    @RequestMapping(value = "/faculties/{facultyId}")
    public String viewFaculty(@PathVariable("facultyId") int facultyId, HttpServletRequest request) {
        Faculty faculty = personService.getFaculty(facultyId);
        if (faculty != null) {
            request.setAttribute("faculty", faculty);
            List<Person> facultymates = new ArrayList<Person>(faculty.getPersons());
            Collections.sort(facultymates, new PersonComparatorByRating());
            if (facultymates.size() > 5) {
                request.setAttribute("facultymates", facultymates.subList(0, 5));
            } else {
                request.setAttribute("facultymates", facultymates);
            }
            return "/faculty";
        } else {
            logger.info("There are no faculty with id=" + facultyId);
            return "redirect:/home";
        }

    }


    /**
     * Redirects to page with user's university faculties
     *
     * @return university-page
     */
    @RequestMapping(value = "/faculties")
    public String viewFaculties() {
        return "redirect:/universities/" + personService.findPersonByEmail(getUserEmail())
                .getGroup().getFaculty().getUniversity().getUniversityId();
    }


    /**
     * Looking for university with universityId from request parameters and returns page with university's information
     *
     * @param universityId of university
     * @param request      with parametrs for view-page
     * @return university's page with it's faculties and top-students or your home page, if there are no university with this universityId
     */
    @RequestMapping(value = "/universities/{universityId}")
    public String viewUniversity(@PathVariable("universityId") int universityId, HttpServletRequest request) {
        University university = personService.getUniversity(universityId);
        if (university != null) {
            request.setAttribute("university", university);
            List<Person> universitymates = new ArrayList<Person>(university.getPersons());
            Collections.sort(universitymates, new PersonComparatorByRating());
            if (universitymates.size() > 5) {
                request.setAttribute("universitymates", universitymates.subList(0, 5));
            } else {
                request.setAttribute("universitymates", universitymates);
            }
            return "/university";
        } else {
            logger.info("There are no university with id=" + universityId);
            return "redirect:/home";
        }
    }

    /**
     * Redirects to page with universities information
     *
     * @param model
     * @return universities page
     */
    @RequestMapping(value = "/universities")
    public String viewUniversities(Map model) {
        model.put("universities", personService.getAllUniversities());
        return "/universities";
    }


    /**
     * Add person to your friend. But while he doesn't confrim friendship, you don't see him in your friendlist
     *
     * @param personId of person
     * @return redirect to person's page with message or to your home page, if there are no such person or it's you
     */
    @RequestMapping(value = "/persons/{personId}/addfriend")
    public String addFriend(@PathVariable("personId") int personId) {
        Person personWhoSend = personService.findPersonByEmail(getUserEmail());
        Person personWhoGet = personService.getPerson(personId);
        if ((personWhoGet != null) && (personWhoGet.getPersonId() != personWhoSend.getPersonId())) {
            Friendship friendship = new Friendship();
            friendship.setPersonWhoProposedFriendship(personWhoSend);
            friendship.setPersonWhoGotFriendshipPropose(personWhoGet);
            friendshipService.createFriendship(friendship);
            return "redirect:/persons/" + personId;
        } else {
            return "redirect:/home";
        }
    }

    /**
     * Deletes friend from your friendlist
     *
     * @param personId of person
     * @return person's page with message or your home page, if there are no such person or he is not your friend
     */
    @RequestMapping(value = "/persons/{personId}/deletefriend")
    public String deleteFriend(@PathVariable("personId") int personId) {
        Person personWhoSend = personService.findPersonByEmail(getUserEmail());
        Person personWhoGet = personService.getPerson(personId);
        List<Person> friends = new ArrayList<Person>(personWhoSend.getAllFriends());
        if ((personWhoGet != null) && (friends.contains(personWhoGet))) {
            Friendship friendship = friendshipService.findFriendshipByPersons(personWhoSend, personWhoGet);
            friendshipService.deleteFriendship(friendship);
            return "redirect:/persons/" + personId;
        } else {
            return "redirect:/home";
        }
    }

    /**
     * Redirects to your friend's page
     *
     * @param model with parameters for view-page
     * @return your friend's page
     */
    @RequestMapping(value = "/persons")
    public String showFriends(Map model) {
        Person person = personService.findPersonByEmail(getUserEmail());
        List<Person> friends = new ArrayList<Person>(person.getConfirmedFriends());
        Collections.sort(friends, new PersonComparatorByRating());
        model.put("friends", friends);
        model.put("friendscount", friends.size());
        return "/friends";
    }

    /**
     * Redirects to your unconfirmed friends page
     *
     * @param model with parameters for view-page
     * @return your unconfirmed friends page
     */
    @RequestMapping(value = "/newfriends")
    public String showNewFriends(Map model) {
        Person person = personService.findPersonByEmail(getUserEmail());
        model.put("friends", person.getUnconfirmedFriends());
        return "/newfriends";
    }

    /**
     * Confirm person's friendship propose
     *
     * @param personId of person
     * @return unconfirmed friends page with message or your home page if person didn't propose friendship
     */
    @RequestMapping(value = "/newfriends/{personId}/confirm")
    public String confirmFriendship(@PathVariable("personId") int personId) {
        Person personWhoSend = personService.findPersonByEmail(getUserEmail());
        Person personWhoGet = personService.getPerson(personId);
        List<Person> friends = new ArrayList<Person>(personWhoSend.getAllFriends());
        if ((personWhoGet != null) && (friends.contains(personWhoGet))) {
            Friendship friendship = friendshipService.findFriendshipByPersons(personWhoSend, personWhoGet);
            friendshipService.confirmFriendship(friendship);
            return "redirect:/newfriends";
        } else {
            return "redirect:/home";
        }
    }

    /**
     * Rejects person's friendship propose
     *
     * @param personId of person
     * @return unconfirmed friends page of your home page with message if person didn't propose friendship
     */
    @RequestMapping(value = "/newfriends/{personId}/rejectfriend")
    public String rejectFriendship(@PathVariable("personId") int personId) {
        Person personWhoSend = personService.findPersonByEmail(getUserEmail());
        Person personWhoGet = personService.getPerson(personId);
        List<Person> friends = new ArrayList<Person>(personWhoSend.getAllFriends());
        if ((personWhoGet != null) && (friends.contains(personWhoGet))) {
            Friendship friendship = friendshipService.findFriendshipByPersons(personWhoSend, personWhoGet);
            friendshipService.deleteFriendship(friendship);
            return "redirect:/newfriends";
        } else {
            return "redirect:/home";
        }
    }
}